#include<iostream>
#include<queue>
#include<vector>
#include<fstream>
#include<iomanip>
#include<algorithm>
#include<ctime>
#include<string>
#include<sstream>

using namespace std;

// 客户数据结构
struct Customer
{
    int id;
    int arrivalTime;
    int serviceTime;
    int startTime = -1;
    int leaveTime = -1;
    int waitTime() const{
        return startTime == -1 ? -1 : startTime - arrivalTime;
    }
    int totalTime() const{
        return leaveTime == -1 ? -1 : leaveTime - arrivalTime;
    }
};

// 窗口结构
struct BankWindow
{
    queue<Customer> waitingQueue;
    int busyUntil = 0;
};

// 事件类型枚举
enum class EventType
{
    Arrival,
    Departure
};

// 事件结构
struct Event
{
    int time;
    EventType type;
    Customer customer;
    int windowIndex;
};

// 银行系统主类
class BankSimulator{
private:
    int openTime;
    int closeTime;
    int windowNum;
    int customerNum;
    vector<BankWindow> windows;
    vector<Customer> customers;
    vector<Event> events;

    // 事件比较器
    struct EventCompare
    {
        bool operator()(const Event& e1, const Event& e2) const{
            return e1.time > e2.time;
        }
    };
    priority_queue<Event, vector<Event>, EventCompare> eventQueue;

public:
    BankSimulator(int openTime, int closeTime, int windowNum, int customerNum)
    : openTime(openTime), closeTime(closeTime), windowNum(windowNum), customerNum(customerNum)
    {
        windows.resize(windowNum);
    }

    // 解析HH:MM格式为分钟（新增：支持正确输入格式）
    int parseTime(const string& timeStr) {
        stringstream ss(timeStr);
        string hhStr, mmStr;
        getline(ss, hhStr, ':');
        getline(ss, mmStr);
        int hh = stoi(hhStr);
        int mm = stoi(mmStr);
        return hh * 60 + mm;
    }

    // 格式化分钟为HH:MM（保留并使用）
    string formatTime(int minutes){
        int hours = minutes / 60;
        int mins = minutes % 60;
        stringstream ss;
        ss << setw(2) << setfill('0') << hours << ":" 
           << setw(2) << setfill('0') << mins;
        return ss.str();
    }

    // 生成客户数据（修复：随机数种子类型转换）
    void generateCustomers(int customerNum){
        srand((unsigned int)time(NULL));
        for(int i = 0; i < customerNum; i++){
            int arrivalTime = rand() % (closeTime - openTime) + openTime;
            int service = 5 + rand() % 25;
            customers.push_back(Customer{i+1, arrivalTime, service});
            eventQueue.push(Event{arrivalTime, EventType::Arrival, customers.back(), -1});
        }
    }

    // 处理到达事件（优化：去掉多余的队列长度判断）
    void handleArrival(const Event& e){
        int shortest = 0;
        for(int i = 1; i < windowNum; i++){
            if(windows[i].waitingQueue.size() < windows[shortest].waitingQueue.size()){
                shortest = i;
            }
        }
        BankWindow& win = windows[shortest];
        win.waitingQueue.push(e.customer);

        if(win.busyUntil <= e.time){
            processNextCustomer(shortest,e.time);
        }
    }

    // 处理离开事件（保持不变）
    void handleDeparture(const Event& e){
        BankWindow& win = windows[e.windowIndex];
        customers[e.customer.id - 1] = e.customer;
        if(!win.waitingQueue.empty()){
            processNextCustomer(e.windowIndex, e.time);
        }
    }

    // 处理窗口下一个客户（保持不变）
    void processNextCustomer(int windowIndex, int currentTime){
        BankWindow& win = windows[windowIndex];
        if(win.waitingQueue.empty()) return;

        Customer customer = win.waitingQueue.front();
        win.waitingQueue.pop();
        customer.startTime = max(currentTime, customer.arrivalTime);
        customer.leaveTime = customer.startTime + customer.serviceTime;
        win.busyUntil = customer.leaveTime;
        eventQueue.push(Event{customer.leaveTime, EventType::Departure, customer, windowIndex});
    }

    // 运行模拟（修复：处理关门后未服务客户）
    void runSimulation(){
        while(!eventQueue.empty()){
            Event e = eventQueue.top();
            eventQueue.pop();

            // 跳过关门后的到达事件，标记为未服务
            if(e.type == EventType::Arrival && e.time > closeTime){
                customers[e.customer.id - 1].leaveTime = -1;
                continue;
            }

            if(e.time > closeTime) continue;
            if(e.type == EventType::Arrival){
                handleArrival(e);
            }else{
                handleDeparture(e);
            }
            events.push_back(e);
        }

        // 清理窗口中未服务的客户
        for(auto& win : windows){
            while(!win.waitingQueue.empty()){
                Customer c = win.waitingQueue.front();
                win.waitingQueue.pop();
                customers[c.id - 1].leaveTime = -1;
            }
        }
    }

    // 输出结果（修复：使用格式化时间、统计未服务客户）
    void printResult(){ 
        ofstream logFile("bank_log.txt");
        if(!logFile.is_open()){
            cout << "错误：无法创建日志文件！" << endl;
            return;
        }

        logFile << "客户ID\t到达时间\t开始服务时间\t离开时间\t等待时间\t逗留时间\t服务状态\n";
        logFile << "----------------------------------------------------------------------------------------\n";
        
        int totalStayTime = 0;
        int servedNum = 0;

        for(auto& c : customers){
            logFile << c.id << "\t"
                    << formatTime(c.arrivalTime) << "\t";

            if(c.leaveTime == -1){
                logFile << "---\t\t" << "---\t\t" << "---\t\t" << "---\t\t" << "未服务（银行已关门）\n";
                continue;
            }

            servedNum++;
            int waitT = c.waitTime();
            int stayT = c.totalTime();
            totalStayTime += stayT;

            logFile << formatTime(c.startTime) << "\t"
                    << formatTime(c.leaveTime) << "\t"
                    << waitT << "分钟\t\t"
                    << stayT << "分钟\t\t"
                    << "已服务\n";
        }

        // 修正平均逗留时间计算（仅统计已服务客户）
        float avgStayTime = servedNum > 0 ? (float)totalStayTime / servedNum : 0.0f;
        logFile << "\n===========================================\n";
        logFile << "统计结果：\n";
        logFile << "总客户数：" << customerNum << "\n";
        logFile << "已服务客户数：" << servedNum << "\n";
        logFile << "未服务客户数：" << customerNum - servedNum << "\n";
        logFile << "平均逗留时间：" << fixed << setprecision(2) << avgStayTime << "分钟\n";
        logFile.close();

        // 控制台输出统计结果
        cout << "\n===========================================\n";
        cout << "模拟结果统计：\n";
        cout << "总客户数：" << customerNum << "\n";
        cout << "已服务客户数：" << servedNum << "\n";
        cout << "未服务客户数：" << customerNum - servedNum << "\n";
        cout << "平均逗留时间：" << fixed << setprecision(2) << avgStayTime << "分钟\n";
        cout << "===========================================\n";
    }
};

// 主函数（修复：支持HH:MM格式输入）
int main(){ 
    string openTimeStr, closeTimeStr;
    int windowNum, customerNum;

    cout << "===== 银行排队系统模拟 =====" << endl;
    cout << "请输入营业开始时间（格式：HH:MM，例如09:00）：";
    cin >> openTimeStr;
    cout << "请输入营业结束时间（格式：HH:MM，例如17:00）：";
    cin >> closeTimeStr;
    cout << "请输入窗口数量：";
    cin >> windowNum;
    cout << "请输入客户数量：";
    cin >> customerNum;

    BankSimulator bank(
        bank.parseTime(openTimeStr),
        bank.parseTime(closeTimeStr),
        windowNum,
        customerNum
    );

    bank.generateCustomers(customerNum);
    bank.runSimulation();
    bank.printResult();

    cout << "\n模拟结束，详细结果已保存到 bank_log.txt 文件中。" << endl;
    return 0;
}

